package com.service.business.otc.controller;

import com.beust.jcommander.internal.Lists;
import com.service.business.base.dto.LoginUserSession;
import com.service.business.base.service.ConfigService;
import com.service.business.member.service.MemberStoreService;
import com.service.business.otc.controller.rep.OtcOrderDetailPageRep;
import com.service.business.support.MemberStoreLockUtils;
import com.service.business.support.OtcOrderLockUtils;
import com.service.core.exception.CommonException;
import com.service.core.rest.BaseController;
import com.service.core.rest.request.PageRequest;
import com.service.core.rest.response.BaseResponse;
import com.service.core.rest.response.OneResponse;
import com.service.core.rest.response.PageResponse;
import com.service.dao.constants.ConfigConstants;
import com.service.dao.enums.OtcDetailTypeEnum;
import com.service.dao.enums.OtcTypeEnum;
import com.service.business.framework.log.RequestLog;
import com.service.business.otc.controller.rep.OtcOrderDetailRep;
import com.service.business.otc.controller.rep.OtcOrderPageRep;
import com.service.business.otc.controller.req.OtcOrderDetailPageReq;
import com.service.business.otc.controller.req.OtcOrderPageReq;
import com.service.business.otc.controller.req.OrderCreateReq;
import com.service.business.otc.controller.req.OrderTradeReq;
import com.service.business.otc.service.OtcOrderDetailService;
import com.service.business.otc.service.OtcOrderService;
import com.service.business.support.SessionUtil;
import com.service.dao.model.MemberStore;
import com.service.dao.model.OtcOrder;
import com.service.dao.model.SysConfig;
import org.redisson.RedissonRedLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.ObjectUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/otc-order")
public class OtcOrderController extends BaseController {

    @Autowired
    private OtcOrderService otcOrderService;
    @Autowired
    private OtcOrderDetailService otcOrderDetailService;
    @Autowired
    private MemberStoreService memberStoreService;
    @Autowired
    private SessionUtil sessionUtil;
    @Autowired
    private ConfigService configService;
    @Autowired
    private OtcOrderLockUtils lockUtils;

    @RequestLog("创建卖单")
    @PostMapping("/create/sell-order")
    public BaseResponse createOtcSellOrder(@RequestBody @Validated OrderCreateReq orderCreateReq) {
        // 创建卖单 有一个正在进行中中的买单话就不能再创建 冻结金额 减去钱包的钱（注意加锁）       加锁（memberId+coinId）
        createOtcOrder(orderCreateReq, OtcTypeEnum.SELL);
        return successSaveBaseResponse();
    }

    @RequestLog("创建买单")
    @PostMapping("/create/buy-order")
    public BaseResponse createOtcBuyOrder(@RequestBody @Validated OrderCreateReq orderCreateReq) {
        // 同创建买单 加锁（memberId+coinId）
        createOtcOrder(orderCreateReq, OtcTypeEnum.BUY);
        return successSaveBaseResponse();
    }

    private void createOtcOrder(OrderCreateReq orderCreateReq, OtcTypeEnum otcType) {
        LoginUserSession session = sessionUtil.getUser();
        if(session.getStoreFreezeStatus() == com.service.dao.enums.MemberEnums.StoreStatus.FROZEN.getCode()){
            throw new CommonException("账户资产已冻结，如有疑问请联系客服","account_assets_frozen");
        }
//        orderCreateReq.setMemberId(session.getUserId());
//        Map<String, SysConfig> configMap = configService.getConfigMapByGroup(ConfigConstants.Group.OTC.getCode());
//        String lockCoinName;
//        if (ObjectUtils.nullSafeEquals(otcType.getType(), OtcTypeEnum.SELL.getType())) {
//            lockCoinName = configMap.get(ConfigConstants.OTC_COIN_TYPE_ID).getConfOptions();
//        } else {
//            lockCoinName = configMap.get(ConfigConstants.OTC_TRADE_COIN_TYPE_ID).getConfOptions();
//        }
//        MemberStore lockStore = memberStoreService.getMemberStore(session.getUserId(), lockCoinName);
//        List<String> lockKeyList = Lists.newArrayList();
//        lockKeyList.add(MemberStoreLockUtils.buildStoreKey(lockStore.getMemberId(), lockStore.getId()));
//        lockKeyList.add(OtcOrderLockUtils.buildKey(lockStore.getMemberId()));
//        RedissonRedLock redLock = lockUtils.getRedLock(lockKeyList);
//        if (lockUtils.redLockTryLock(redLock)) {
//            try {
//                otcOrderService.creatOtcOrder(orderCreateReq, otcType.getType(), configMap);
//            } finally {
//                redLock.unlock();
//            }
//        }
    }

    @RequestLog("卖单分页查询")
    @PostMapping("/page/sell")
    public PageResponse<OtcOrderPageRep> pageSellOrder(@RequestBody PageRequest pageRequest) {
        return successQueryPageResponse(otcOrderService.pageOrder(OtcTypeEnum.SELL.getType(), pageRequest));
    }

    @RequestLog("买单分页查询")
    @PostMapping("/page/buy")
    public PageResponse<OtcOrderPageRep> pageBuyOrder(@RequestBody PageRequest pageRequest) {
        return successQueryPageResponse(otcOrderService.pageOrder(OtcTypeEnum.BUY.getType(), pageRequest));
    }

    @PostMapping("page/member-order/sell")
    public PageResponse<OtcOrderPageRep> pageUserSellOrder(@RequestBody OtcOrderPageReq pageRequest) {
        pageRequest.setOtcType(OtcTypeEnum.SELL.getType());
        pageRequest.setMemberId(sessionUtil.getUser().getUserId());
        return successQueryPageResponse(otcOrderService.pageUserOrder(pageRequest));
    }

    @PostMapping("page/member-order/buy")
    public PageResponse<OtcOrderPageRep> pageUserBuyOrder(@RequestBody OtcOrderPageReq pageRequest) {
        pageRequest.setOtcType(OtcTypeEnum.BUY.getType());
        pageRequest.setMemberId(sessionUtil.getUser().getUserId());
        return successQueryPageResponse(otcOrderService.pageUserOrder(pageRequest));
    }

    @PostMapping("page/member-trade-order/buy")
    public PageResponse<OtcOrderDetailPageRep> pageUserBuyOrder(@RequestBody OtcOrderDetailPageReq pageRequest) {
        return pageUserOtcOrderDetail(pageRequest, OtcDetailTypeEnum.BUY);
    }

    @PostMapping("page/member-trade-order/sell")
    public PageResponse<OtcOrderDetailPageRep> pageUserSellOrder(@RequestBody OtcOrderDetailPageReq pageRequest) {
        return pageUserOtcOrderDetail(pageRequest, OtcDetailTypeEnum.SELL);
    }

    private PageResponse<OtcOrderDetailPageRep> pageUserOtcOrderDetail(OtcOrderDetailPageReq pageRequest, OtcDetailTypeEnum typeEnum) {
        LoginUserSession userSession = sessionUtil.getUser();
        pageRequest.setMemberId(userSession.getUserId());
        pageRequest.setType(typeEnum.getType());
        return successQueryPageResponse(otcOrderDetailService.pageUserOrderDetail(pageRequest));
    }

    @GetMapping("/detail/{orderNo}")
    public OneResponse<OtcOrderDetailRep> orderDetail(@PathVariable String orderNo) {
        return successQueryOneResponse(otcOrderService.getDetail(orderNo));
    }

    @RequestLog("OTC-买")
    @PostMapping("/buy")
    public BaseResponse buy(@RequestBody @Validated OrderTradeReq OrderTradeReq) {
        //校验买家钱包余额是否充足 创建交易明细 更新卖家钱包冻结金额 更新买家交易币种的余额 更新买家买入的币种账户余额 操作对应的流水
        tradingOtcOrder(OrderTradeReq, OtcDetailTypeEnum.BUY);
        return successSaveBaseResponse();
    }

    @RequestLog("OTC-卖")
    @PostMapping("/sell")
    public BaseResponse sell(@RequestBody @Validated OrderTradeReq OrderTradeReq) {
        //立即卖出 校验卖家钱包余额是否充足 更新买家钱包冻结金额 更新卖家钱包余额、更新买家买入币种的账户余额 操作对应的流水
        tradingOtcOrder(OrderTradeReq, OtcDetailTypeEnum.SELL);
        return successSaveBaseResponse();
    }

    private void tradingOtcOrder(OrderTradeReq orderTradeReq, OtcDetailTypeEnum typeEnum) {
        LoginUserSession userSession = sessionUtil.getUser();
        if(userSession.getStoreFreezeStatus() == com.service.dao.enums.MemberEnums.StoreStatus.FROZEN.getCode()){
            throw new CommonException("账户资产已冻结，如有疑问请联系客服","account_assets_frozen");
        }
        OtcOrder order = otcOrderService.getOrderByOrderNo(orderTradeReq.getOtcNo());
        List<String> lockKey = Lists.newArrayList();
        lockKey.add(OtcOrderLockUtils.buildOrderKey(orderTradeReq.getOtcNo()));
        List<MemberStore> storeList = Lists.newArrayList(
                memberStoreService.getMemberStore(order.getMemberId(), order.getTradeCoinsName()),
                memberStoreService.getMemberStore(order.getMemberId(), order.getCoinsName()),
                memberStoreService.getMemberStore(userSession.getUserId(), order.getTradeCoinsName()),
                memberStoreService.getMemberStore(userSession.getUserId(), order.getCoinsName())
        );
        lockKey.addAll(MemberStoreLockUtils.buildStoreKey2List(storeList));
        RedissonRedLock redLock = lockUtils.getRedLock(lockKey);
        if (lockUtils.redLockTryLock(redLock)) {
            try {
                otcOrderService.tradingOtcOrder(orderTradeReq, typeEnum, userSession);
            } finally {
                redLock.unlock();
            }
        }
    }

    @PostMapping("/cancel/{orderNo}")
    public BaseResponse cancel(@PathVariable String orderNo) {
        LoginUserSession userSession = sessionUtil.getUser();
        OtcOrder order = otcOrderService.getOrderByOrderNo(orderNo);
        List<String> lockKey = Lists.newArrayList();
        lockKey.add(OtcOrderLockUtils.buildOrderKey(orderNo));
        List<MemberStore> storeList = Lists.newArrayList(
                memberStoreService.getMemberStore(userSession.getUserId(), order.getTradeCoinsName()),
                memberStoreService.getMemberStore(userSession.getUserId(), order.getCoinsName())
        );
        lockKey.addAll(MemberStoreLockUtils.buildStoreKey2List(storeList));
        RedissonRedLock redLock = lockUtils.getRedLock(lockKey);
        if (lockUtils.redLockTryLock(redLock)) {
            try {
                otcOrderService.cancelOrder(orderNo);
            } finally {
                redLock.unlock();
            }
        }
        return successSaveBaseResponse();
    }

    @RequestLog
    @GetMapping("/config")
    public BaseResponse tradeConfig() {
        return successQueryOneResponse(otcOrderService.getOtcConfig());
    }
}
